package com.gitee.wsl.ext.json

import com.gitee.wsl.Lib
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationException
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromJsonElement
import kotlin.reflect.KClass

@OptIn(ExperimentalSerializationApi::class)
object JsonExt {
    val formatter by lazy(LazyThreadSafetyMode.PUBLICATION) {
        Json {
            ignoreUnknownKeys = true // JSON和数据模型字段可以不匹配
            coerceInputValues = true // 如果JSON字段是Null则使用默认值
            allowStructuredMapKeys = true
        }
    }

    val formatterPretty by lazy(LazyThreadSafetyMode.PUBLICATION) {
        Json {
            ignoreUnknownKeys = true // JSON和数据模型字段可以不匹配
            coerceInputValues = true // 如果JSON字段是Null则使用默认值
            prettyPrint = true
            prettyPrintIndent = "  "
        }
    }

    inline fun <reified T : Any> fromJson(json: String): T = formatter.decodeFromString(json)
    inline fun <reified T : Any> fromJson(json: String, clazz: KClass<T>): T = formatter.decodeFromString(json)

    /*inline fun <reified T: Any> fromJson(json: String, clazz: Class<T>) = formatter.decodeFromString<T>(json)
    inline fun <reified T: Any> fromJson(json: String, type: Type) = formatter.decodeFromString<T>(json)*/

    inline fun <reified T: Any> toJson(bean: T) = formatter.encodeToString(bean)
    inline fun <reified T: Any> toJsonPretty(bean: T) = formatterPretty.encodeToString(bean)

    //fun asConverterFactory(mediaType: MediaType) = formatter.asConverterFactory(mediaType)
}

inline fun <reified T> Json.decodeFromStringOrNull(json: String?): T? {
    if (json == null) return null
    return try {
        decodeFromString(json)
    } catch (e: SerializationException) {
        null
    }
}


inline fun <reified T> String?.decodeJsonFromString(base: Json = json) = base.decodeFromStringOrNull<T>(this)

inline fun <reified T> T.encodeToJsonString(base: Json = json) = base.encodeToString(this)

fun <T> T.encodeToJsonString(base: Json = json, serializer: SerializationStrategy<T>,) = base.encodeToString(serializer,this)


val json: Json by lazy {
    Json {
    coerceInputValues = true
    encodeDefaults = true
    ignoreUnknownKeys = true
    isLenient = true
  }
}

val Lib.defaultJson: Json get() = json

@Throws(Throwable::class)
inline fun <reified T> Map<*, *>.decoded(): T = json.decodeFromJsonElement(toJsonElement())
